home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Applications
/
Audio
/
Spectro
/
Source
/
Spectro.m
< prev
next >
Wrap
Text File
|
1994-05-06
|
16KB
|
506 lines
/* Generated by Interface Builder */
#import "Spectro.h"
#import "SpectrumView.h"
#import "WaterfallView.h"
#import "WaterfallComputer.h"
#import "SignalProcessor.h"
#import <appkit/appkit.h>
#import <soundkit/soundkit.h>
#import <math.h>
#import <string.h>
#import <stdio.h>
int data_size,power_of_four,window_size,num_frames,total_data,s_rate,mono_file;
float f[16384],freq_max;
BOOL running_analysis = FALSE,one_time = FALSE,waterfall = FALSE;
char window_type[200];
int firstSample,sampleCount;
float ceiling,flor;
@implementation Spectro
- changeFreqMax:sender
{
int i;
freq_max = [[sender cellAt: 0 : 4] floatValue];
if (freq_max>0.5*s_rate) freq_max = 0.5 * s_rate;
for (i=1;i<5;i++) {
[[freqRange cellAt: 0 : i] setIntValue: i * 0.25 * freq_max];
[[freqRange2 cellAt: 0 : i] setIntValue: i * 0.25 * freq_max];
}
[myView setFreqRange: freq_max andAmpRange: [myView ampRange]];
[myView clear];
[myView placeVerticals: 0.25];
[self calculate:nil];
return self;
}
- selectionChanged:sender
{
mySound = [sender sound];
[mySound compactSamples];
[self setup: sender];
if ([goOnSelect state]) [self calculate:self];
return self;
}
- setup:sender
{
int i;
[[soundView docView] getSelection:&firstSample size:&sampleCount];
if ((firstSample + sampleCount)>[[[soundView docView] sound] sampleCount]) sampleCount = [[[soundView docView] sound] sampleCount] - firstSample;
num_frames = sampleCount / [windowSize intValue] * 2 - 1;
if (num_frames<1) num_frames = 0;
s_rate = [mySound samplingRate];
[numFrames setIntValue: num_frames];
freq_max = [[freqRange cellAt: 0 : 4] floatValue];
if (freq_max>0.5*s_rate) freq_max = 0.5 * s_rate;
for (i=1;i<5;i++) {
[[freqRange cellAt: 0 : i] setIntValue: i * 0.25 * freq_max];
[[freqRange2 cellAt: 0 : i] setIntValue: i * 0.25 * freq_max];
}
flor = [[viewLimit cellAt: 4: 0] floatValue];
[myView setFreqRange: freq_max andAmpRange: flor];
[beginTime setDoubleValue: (double) firstSample / s_rate];
[self changeTimeSetups: numFrames];
return self;
}
- calculate:sender
{
// int temp_num_frames;
// mySound = [[soundView docView] sound];
// [mySound compactSamples];
// temp_num_frames = [mySound sampleCount] / [windowSize intValue] * 2 - 1;
// num_frames = [numFrames intValue];
// if (temp_num_frames < num_frames) {
// num_frames = temp_num_frames;
// [numFrames setIntValue: num_frames];
// [self changeTimeSetups: numFrames];
// }
one_time = TRUE;
[self doSpectrum];
one_time = FALSE;
return self;
}
- knockItOff:sender
{
one_time = FALSE;
return self;
}
- (int) passThisToWFViewPlease: (float *) f // this is sent by WaterfallComputer to draw views
{ // It's here so later we can put the computation into a different thread
// We're faking that now by checking the stop button explicitly each time.
NXRect buttonBounds;
NXPoint mousePosition;
int mouseDown,windowIsKey;
[myWaterfallView drawNext: f];
[[stopButton window] getMouseLocation: &mousePosition];
[stopButton getBounds: &buttonBounds];
PSbuttondown(&mouseDown);
// windowIsKey = [[stopButton window] isKeyWindow];
if ([stopButton mouse:&mousePosition inRect: &buttonBounds] && mouseDown) return 1;
else return 0;
}
- doSpectrum
{
float temp_f[16384];
int i;
float timeDelta,timeBegin;
unsigned char *data;
short *linear_data;
mySound = [[soundView docView] sound];
if (mySound) {
[mySound compactSamples];
[[soundView docView] getSelection:&firstSample size:&sampleCount];
if ((firstSample + sampleCount)>[[[soundView docView] sound] sampleCount])
sampleCount = [[[soundView docView] sound] sampleCount] - firstSample;
data = [mySound data];
linear_data = (short *) data;
strcpy(window_type,[windowType stringValue]);
flor = [[viewLimit cellAt: 4: 0] floatValue];
ceiling = 2.0 * 65536.0 * 65536.0 * window_size;
mono_file = 2;
if ([mySound channelCount]>1) {
mono_file = NXRunAlertPanel("Spectro is Confused","The current sound is stereo.\
What should I transform?","Both Mixed","Right","Left");
printf("%i\n",mono_file);
}
if (num_frames>1 && one_time) {
for (i=0;i<data_size;i++) temp_f[i] = f[i];
if (!myWaterfallComputer) {
myWaterfallComputer = [[WaterfallComputer allocFromZone:[self zone]] init];
[myWaterfallComputer setSignalProcessor: mySignalProcessor];
[myWaterfallComputer setApp: self];
}
[myWaterfallView setup: num_frames length: (int) (data_size * freq_max / s_rate)];
if ([mySound dataFormat]==1)
[myWaterfallComputer computeThisCodex: data];
else
[myWaterfallComputer computeThisLinear: linear_data];
timeDelta = ([totalSeconds floatValue] / num_frames) * (num_frames + 1) * 0.25;
timeBegin = [beginTime floatValue];
for (i=0;i<5;i++) {
[[wfTimes cellAt: 4-i : 0] setFloatValue: timeBegin];
timeBegin += timeDelta;
}
[myView clear];
[frameSlider setFloatValue: 0.0];
[self sliderChange: frameSlider];
[myView placeVerticals: 0.25];
[myView drawSpectrum: (int) (data_size * freq_max / s_rate) array: f];
s_rate = [mySound samplingRate];
if (freq_max==0) freq_max = 0.5 * s_rate;
for (i=1;i<5;i++) {
[[freqRange cellAt: 0 : i] setIntValue: i * 0.25 * freq_max];
[[freqRange2 cellAt: 0 : i] setIntValue: i * 0.25 * freq_max];
}
[myView setFreqRange: freq_max andAmpRange: flor];
[myView placeHorizontals: 0.25];
}
else {
for (i=0;i<data_size;i++) temp_f[i] = f[i];
if ([mySound dataFormat]==1)
for (i=0;i<window_size;i++) f[i] = (float) SNDiMulaw(data[i + firstSample]);
else {
if (mono_file==2)
for (i=0;i<window_size;i++) f[i] = (float) linear_data[i +firstSample];
if (mono_file==1)
for (i=0;i<window_size;i++) f[i] = (float) (linear_data[2*(i +firstSample)] +
linear_data[2*(i + firstSample) + 1]) * 0.5;
if (mono_file==0)
for (i=0;i<window_size;i++) f[i] = (float) linear_data[2*(i + firstSample) + 1];
if (mono_file==-1)
for (i=0;i<window_size;i++) f[i] = (float) linear_data[2*(i + firstSample)];
}
for (i=window_size;i<data_size;i++) f[i] = 0.0;
[mySignalProcessor window: window_size array: f type: window_type phase: FALSE];
[mySignalProcessor fhtRX4: power_of_four array: f];
[mySignalProcessor logMag: data_size array: f floor: flor ceiling: ceiling];
[myView drawSpectrum: (int) (data_size * freq_max / s_rate) array: temp_f erase: TRUE];
[myView placeVerticals: 0.25];
[myView drawSpectrum: (int) (data_size * freq_max / s_rate) array: f];
s_rate = [mySound samplingRate];
if (freq_max==0) freq_max = 0.5 * s_rate;
for (i=1;i<5;i++) {
[[freqRange cellAt: 0 : i] setIntValue: i * 0.25 * freq_max];
[[freqRange2 cellAt: 0 : i] setIntValue: i * 0.25 * freq_max];
}
[myView setFreqRange: freq_max andAmpRange: flor];
[myView placeHorizontals: 0.25];
}
}
return self;
}
- changeZPFactor: sender
{
double temp;
window_size = [windowSize intValue];
data_size = window_size * [zpFactor floatValue];
num_frames = [numFrames intValue];
temp = log((double) data_size) / log(4.0);
if (temp>7.0) temp=7.0;
power_of_four = temp + .999;
data_size = pow(4.0,power_of_four);
[zpFactor setFloatValue: ((float) data_size / (float) window_size)];
if (s_rate>0) temp = (float) window_size / (float) s_rate * 0.5;
[hopTime setDoubleValue: temp];
[windowTime setDoubleValue: temp * 2.0];
[totalSeconds setDoubleValue: temp * [numFrames doubleValue]];
[self setup: self];
[self calculate: self];
return self;
}
- changeWindowSize:sender
{
[zpFactor setIntValue: 1];
[myView clear];
[self setup:self];
[self calculate:self];
return self;
}
- changeTimeSetups: sender
{
double temp;
window_size = [windowSize intValue];
data_size = window_size * [zpFactor floatValue];
num_frames = [numFrames intValue];
temp = log((double) data_size) / log(4.0);
if (temp>7.0) temp=7.0;
power_of_four = temp + .999;
data_size = pow(4.0,power_of_four);
[zpFactor setFloatValue: ((float) data_size / (float) window_size)];
mySound = [[soundView docView] sound];
s_rate = [mySound samplingRate];
if (s_rate>0) temp = (float) window_size / (float) s_rate* 0.5;
[hopTime setDoubleValue: temp];
[windowTime setDoubleValue: temp * 2.0];
[totalSeconds setDoubleValue: temp * [numFrames doubleValue]];
return self;
}
- changeViewLimit:sender
{
int temp,i;
temp = [sender intValue];
if (temp>0) temp = -temp;
for (i=0;i<4;i++) [[viewLimit cellAt: i : 0] setIntValue: temp * i / 4];
[myView clear];
s_rate = [mySound samplingRate];
if (freq_max==0) freq_max = 0.5 * s_rate;
for (i=1;i<5;i++) {
[[freqRange cellAt: 0 : i] setIntValue: i * 0.25 * freq_max];
[[freqRange2 cellAt: 0 : i] setIntValue: i * 0.25 * freq_max];
}
[myView setFreqRange: freq_max andAmpRange: temp];
[self calculate:nil];
return self;
}
- timeChange:sender
{
float temp;
int plot;
temp = [sender floatValue] - [beginTime floatValue];
plot = temp / [hopTime floatValue];
temp = plot / ([numFrames floatValue]);
[frameSlider setFloatValue: temp];
[self sliderChange: frameSlider];
return self;
}
- frameChange:sender
{
float temp;
int plot;
plot = [sender intValue];
temp = plot / (1.5 + [numFrames floatValue]);
[frameSlider setFloatValue: temp];
[self sliderChange: frameSlider];
return self;
}
- sliderChange:sender
{
float temp,temp_f[17000];
int plot,k,i;
unsigned char *data;
short *linear_data;
mySound = [[soundView docView] sound];
if (mySound) {
[mySound compactSamples];
[[soundView docView] getSelection:&firstSample size:&sampleCount];
if ((firstSample + sampleCount)>[[[soundView docView] sound] sampleCount]) sampleCount = [[[soundView docView] sound] sampleCount] - firstSample;
data = [mySound data];
linear_data = (short *) data;
strcpy(window_type,[windowType stringValue]);
flor = [[viewLimit cellAt: 4: 0] floatValue];
ceiling = 2.0 * 65536.0 * 65536.0 * window_size;
temp = [sender floatValue];
plot = temp * (2.5 + [numFrames floatValue]);
[currentTime setFloatValue: [hopTime floatValue] * plot + [beginTime floatValue]];
[currentPlot setIntValue: plot];
if (plot > [numFrames intValue] - 1) plot = [numFrames intValue] - 1;
[myWaterfallView placeTickAt: plot];
for (i=0;i<data_size;i++) temp_f[i] = f[i];
[myView drawSpectrum: (int) (data_size * freq_max / s_rate) array: temp_f erase: TRUE];
k = plot * window_size * 0.5;
if ([mySound dataFormat]==1)
for (i=0;i<window_size;i++) f[i] = (float) SNDiMulaw(data[i +k + firstSample]);
else {
if (mono_file==2)
for (i=0;i<window_size;i++) f[i] = (float) linear_data[i +k+ firstSample];
if (mono_file==1)
for (i=0;i<window_size;i++) f[i] = (float) (linear_data[2*(i +k+ firstSample)] +
linear_data[2*(i + k+ firstSample) + 1]) * 0.5;
if (mono_file==0)
for (i=0;i<window_size;i++) f[i] = (float) linear_data[2*(i + k+ firstSample) + 1];
if (mono_file==-1)
for (i=0;i<window_size;i++) f[i] = (float) linear_data[2*(i +k+ firstSample)];
}
for (i=window_size;i<data_size;i++) f[i] = 0.0;
[mySignalProcessor window: window_size array: f type: window_type phase: FALSE];
[mySignalProcessor fhtRX4: power_of_four array: f];
[mySignalProcessor logMag: data_size array: f floor: flor ceiling: ceiling];
[myView drawSpectrum: (int) (data_size * freq_max / s_rate) array: f];
[myView placeVerticals: 0.25];
[myView drawSpectrum: (int) (data_size * freq_max / s_rate) array: f];
s_rate = [mySound samplingRate];
for (i=1;i<5;i++) {
[[freqRange cellAt: 0 : i] setIntValue: i * 0.25 * freq_max];
[[freqRange2 cellAt: 0 : i] setIntValue: i * 0.25 * freq_max];
}
[myView setFreqRange: freq_max andAmpRange: flor];
[myView placeHorizontals: 0.25];
}
return self;
}
- running:sender
{
double temp;
window_size = [windowSize intValue];
data_size = window_size * [zpFactor floatValue];
num_frames = [numFrames intValue];
temp = window_size / 16024.0;
[hopTime setDoubleValue: temp];
[windowTime setDoubleValue: temp * 2.0];
[totalSeconds setDoubleValue: temp * [numFrames doubleValue]];
temp = log((double) data_size) / log(4.0);
if (temp>7.0) temp=7.0;
power_of_four = temp + .999;
data_size = pow(4.0,power_of_four);
[zpFactor setFloatValue: ((float) data_size / (float) window_size)];
if (sender==loopButton&&[loopButton state]) [myView clear];
if ([loopButton state]) running_analysis = TRUE; else running_analysis = FALSE;
// if (sender==oneTime) one_time = TRUE;
if (running_analysis || one_time) {
mySound = [[soundView docView] sound];
if (!mySound) {
[[soundView docView] setSound: [Sound new]];
mySound = [[soundView docView] sound];
[mySound setDelegate: self];
}
if (running_analysis) {
total_data = window_size;
[mySound setDataSize: window_size
dataFormat: SND_FORMAT_MULAW_8
samplingRate:SND_RATE_CODEC
channelCount: 1
infoSize: 12];
}
[mySound record];
}
return self;
}
- didRecord:sender
{
if (running_analysis) {
[self doSpectrum];
[self running: nil];
}
if (one_time) {
[soundMeter stop:self];
one_time = FALSE;
}
return self;
}
- save:sender
{
char file_name[200];
strcpy(file_name,[fileName stringValue]);
[[[soundView docView] sound] writeSoundfile:file_name];
return self;
}
- zoomOut:sender
{
[[soundView docView] setReductionFactor: [[soundView docView] reductionFactor] * 2.0];
return self;
}
- zoomIn:sender
{
[[soundView docView] setReductionFactor: [[soundView docView] reductionFactor] * 0.5];
return self;
}
- showAll:sender
{
NXRect frame;
double num_samps;
num_samps = [[[soundView docView] sound] sampleCount];
[[soundView docView] setReductionFactor: 1.0];
[[soundView docView] getVisibleRect: &frame];
[[soundView docView] setReductionFactor: num_samps / frame.size.width];
return self;
}
- showSelection:sender
{
NXRect frame;
int beg, size;
double num_samps;
float total_samps;
[[soundView docView] getSelection: &beg size: &size];
num_samps = size;
total_samps = (float) [[[soundView docView] sound] sampleCount];
[[soundView docView] setReductionFactor: 1.0];
[[soundView docView] getVisibleRect: &frame];
[[soundView docView] setReductionFactor: num_samps / frame.size.width];
[[soundView horizScroller] setFloatValue: (float) beg / total_samps];
[soundView display];
return self;
}
- play:sender
{
[[soundView docView] setDelegate: self];
[soundView play:sender];
return self;
}
- stop:sender
{
[soundView stop:sender];
[soundMeter stop:self];
return self;
}
- record:sender
{
[[soundView docView] setDelegate: self];
[soundView record:sender];
return self;
}
- willPlay:sender
{
[soundMeter setSound: [[soundView docView] soundBeingProcessed]];
[soundMeter run:self];
return self;
}
- willRecord:sender
{
[soundMeter setSound: [[soundView docView] soundBeingProcessed]];
[soundMeter run:self];
return self;
}
- didPlay:sender
{
[soundMeter stop:self];
return self;
}
- load:sender
{
char file_name[200];
strcpy(file_name,[fileName stringValue]);
[mySound free];
if (mySound = [Sound newFromSoundfile: file_name]) {
[[soundView docView] setSound: mySound];
[[soundView docView] setDelegate: self];
[self setup:sender];
}
else {
[mySound free];
NXRunAlertPanel("Spectro is Confused","I can't find that file.",NULL,NULL,"OK");
}
return self;
}
@end